_Pragma("once");

#include "INetwork.h"
#include "Ethernet.h"
#include "Lte4gNetwork.h"
#include "SingletonTemplate.h"
#include "ConfigManager.h"
#include "OfflineReason.h"

constexpr int32_t ACTIVE_SHRESHOLD = 0;
constexpr int32_t STOP_START_SHRESHOLD = 4;
constexpr int32_t STOP_START_HARDWARE_SHRESHOLD = 8;
constexpr int32_t RESET_SHRESHOLD = 11;

/**
 * 网络管理
 * @author lizb
 */
class NetworkManager {
    friend class SingletonTemplate<NetworkManager>;

    using MutexType = std::recursive_mutex;

public:


    NetworkManager() : methernet(), mlte4gNetwork(), methernet1("eth1", NetworkType::ETHERNET1) {
        mtype = ConfigManagerSingleton::instance().getConfigInfo().networkType;

        mallNetwork.emplace_back(&methernet);
        mallNetwork.emplace_back(&methernet1);
        mallNetwork.emplace_back(&mlte4gNetwork);
        msize = mallNetwork.size();

        mpactiveNetwork = getActiveNetwork(mtype);
    }

    INetwork* setActiveNetworkInternal(INetwork* network) {
        mpactiveNetwork->stopHardware();

        mpactiveNetwork = network;
        mpactiveNetwork->startHardware();

        return mpactiveNetwork;
    }

    INetwork* setActiveNetwork(const NetworkType& networkType, INetwork* network) {
        std::unique_lock<MutexType> lock(mmutex);

        mpactiveNetwork->stopHardware();//stop()

        mtype = networkType;
        mpactiveNetwork = network;
        mpactiveNetwork->startHardware();//start()

        lock.unlock();
        return mpactiveNetwork;
    }



    INetwork* getNextNetwork(){
       mcurrentIndex = ++mcurrentIndex % msize;
       return mallNetwork.at(mcurrentIndex);
    }



    INetwork* getActiveNetwork(const NetworkType& networkType) {
        INetwork* network;
        switch(networkType) {
        case NetworkType::ETHERNET:
            network = &methernet;
            break;


        case NetworkType::IOT_4G:
            network = &mlte4gNetwork;
            break;

        case NetworkType::ETHERNET1:
            network = &methernet1;
            break;

        case NetworkType::AUTO:
            network = getNextNetwork();

        default:
            break;
        }

        return network;
    }



    void reactiveNetwork(INetwork* const pcurrent, const OfflineReason offlineReason);


    int32_t mretryCount;

    INetwork*volatile mpactiveNetwork;
    Ethernet    methernet;
    Ethernet    methernet1;
    Lte4gNetwork mlte4gNetwork;
    NetworkType mtype;

protected:

    std::vector<INetwork*> mallNetwork;
    std::size_t msize;
    std::size_t mcurrentIndex = 1;

    MutexType mmutex;
};



using NetworkManagerSingleton = SingletonTemplate<NetworkManager>;




